package com.flex.mobile.timer;

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;

import com.flex.mobile.exception.TaxiException;
import com.flex.mobile.util.CalenderUtil;

public class OnceTimer {
   private Timer timer = null;
   private Vector<TimerInternal> timerV = new Vector<TimerInternal>();
   private OnceTimerHandler handler = null;
   private MyTimerTask mtask = null;
   boolean first = true;
   long lastTrigStartTime = 0;
   long lastTrigEndTime = 0;
   static int delay = 20 * 1000;

   private static OnceTimer inst;

   public static OnceTimer getInstance() {
      if (inst == null) {
         synchronized (OnceTimer.class) {
            if (inst == null)
               inst = new OnceTimer();
         }
      }
      return inst;
   }

   private OnceTimer() {
   }

   public void setHandler(OnceTimerHandler hand) {
      handler = hand;
   }

   public void clear() {
      synchronized (timerV) {
         timerV.clear();
      }
   }

   public int size() {
      return timerV.size();
   }

   public void startTimer() throws TaxiException {
      timer = new java.util.Timer();
      if (handler == null)
         throw new TaxiException("");
      mtask = new MyTimerTask();

      if (!"false".equals("true"))
         timer.schedule(mtask, TimerConfig.getFirstTrigDelay(),
               TimerConfig.getTrigPeriod());
   }

   public void registeTimer(long key, long trigTime) {
      synchronized (timerV) {
         TimerInternal ti = new TimerInternal();
         ti.key = key;
         ti.trigTime = trigTime;
         timerV.add(ti);
      }
   }

   public void unregisteTimer(long key) {
      synchronized (timerV) {
         for (int i = 0; i < timerV.size(); i++) {
            TimerInternal ti = (TimerInternal) timerV.get(i);
            if (ti.key == key)
               timerV.remove(i);
         }
      }
   }

   public int getTimerLength() {
      return timerV.size();
   }

   public String logInnerTimerContent() {
      synchronized (timerV) {
         StringBuffer ret = new StringBuffer("");
         ret.append("\n$$$ Now to print timerInner content  .  Timer Length="
               + timerV.size() + " lastStart=" + getTimeDesc(lastTrigStartTime)
               + " lastEnd=" + getTimeDesc(lastTrigEndTime) + " lastDural="
               + (lastTrigEndTime - lastTrigStartTime));
         try {
            for (int i = 0; i < timerV.size(); i++) {
               TimerInternal ti = (TimerInternal) timerV.get(i);

               if (i < 200)
                  ret.append("\n$$$ Timer[" + i + "]  key=" + ti.key
                        + "   TriggerTime="
                        + CalenderUtil.getTimeString(ti.trigTime));
            }
         } catch (Throwable th) {
            ret.append("\n$$$ exception :" + th.getMessage());
            return ret.toString();
         }
         ret.append("\n$$$ TimerInner content print over");

         return ret.toString();
      }
   }

   private static String getTimeDesc(long time) {
      if (time == 0)
         return "";
      else
         return CalenderUtil.getTimeString(time);
   }

   class MyTimerTask extends TimerTask {
      public void run() {
         try {
            runTimerTask();
         } catch (Throwable th) {
         }
      }
   }

   public void runTimerTask() {
      long currentTime = (new Date()).getTime();

      lastTrigStartTime = currentTime;
      lastTrigEndTime = 0;

      if (first) {
         first = false;
      }

      int pos = 0;

      while (true) {
         TimerInternal trigged = null;

         synchronized (timerV) {
            // break condition
            if (pos > timerV.size() - 1)
               break;
            TimerInternal ti = (TimerInternal) timerV.get(pos);
            // if not trigged ,pos++
            if (ti.trigTime <= currentTime) {
               timerV.remove(ti);
               trigged = ti;
            } else
               pos++;
         }
         // do the trig action
         if (trigged != null) {
            handler.timerTrigged(trigged.key);
         }
      }

      lastTrigEndTime = System.currentTimeMillis();
   }

   static class TimerInternal {
      long key;
      long trigTime;

      public String toString() {
         return "{timerID=" + key + ",trig=" + getTimeDesc(trigTime) + "}";
      }
   }

   public void stop() {
      timer.cancel();
      mtask.cancel();
   }

}
